package cn.egame.extraction.multithread.service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;

import cn.egame.common.exception.ExceptionCommonBase;
import cn.egame.common.util.Utils;
import cn.egame.common.web.WebUtils;
import cn.egame.extraction.multithread.file.FileService;
import cn.egame.extraction.multithread.file.FileServiceHandler;
import cn.egame.extraction.multithread.pojo.EfsInfo;
import cn.egame.extraction.multithread.service.filter2.ApplicationFilterChain;
import cn.egame.extraction.multithread.service.filter2.ChainObject;
import cn.egame.extraction.multithread.service.filter2.CheckFileExistsFilter;
import cn.egame.extraction.multithread.service.filter2.CrawlerFileFilter;
import cn.egame.extraction.multithread.service.filter2.FilePathListFilter;
import cn.egame.extraction.multithread.service.filter2.Filter;
import cn.egame.extraction.multithread.service.filter2.FilterChain;
import cn.egame.extraction.multithread.util.ConstVar_EFS;
import cn.egame.extraction.multithread.util.EnumType_EFS.EfsInfoFromType;
import cn.egame.extraction.multithread.util.EnumType_EFS.InputErrorFileAppendType;
import cn.egame.extraction.multithread.util.Util;


public class CrawlerThread implements Runnable {
	public  Logger logger = Logger.getLogger(CrawlerThread.class);
	public  Logger successSyncIdLog = Logger.getLogger("sucessSyncId");
	public  Logger errorSyncIdLog = Logger.getLogger("errorSyncId");
	
	private int threadId;
	private List<EfsInfo> efsInfoList = new ArrayList<EfsInfo>();
	private long readMaxId;
	private long writeMaxId;
	
	private FileService fileService;
	private FileService maxIdfileService;
//	private Filter handler; //处理拉取文件的责任链对象
	private String filename;
	
	
	public FileService getFileService() {
		return fileService;
	}

	public String getFilename() {
		return filename;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}

	public int getThreadId() {
		return threadId;
	}

	public void setThreadId(int threadId) {
		this.threadId = threadId;
	}

	public void setFileService(FileService fileService) {
		this.fileService = fileService;
	}

	public FileService getMaxIdfileService() {
		return maxIdfileService;
	}

	public void setMaxIdfileService(FileService maxIdfileService) {
		this.maxIdfileService = maxIdfileService;
	}

//	public Filter getHandler() {
//		return handler;
//	}
//
//	public void setHandler(Filter handler) {
//		this.handler = handler;
//	}

	public CrawlerThread(int threadId){
		this.threadId = threadId;
//		this.handler = handler;
		init();
	}
	
	private void init(){
		filename = ConstVar_EFS.THREAD_FETCH_BASE_FILE_PATH + threadId;
//		fileService = FileServiceHandler.getInstance(filename);
		fileService = new FileService();
		String maxIdFilename = ConstVar_EFS.MAX_ID_FILE_PATH;
//		maxIdfileService = FileServiceHandler.getInstance(maxIdFilename);
	}
	
	/**
	 * 填充该线程对应的拉取文件
	 */
	public void fillFetchFile(String filePath) throws ExceptionCommonBase{
		synchronized (CrawlerThread.class) {
			
			//获取最大id文件
//			readMaxId = maxIdfileService.getMaxId(ConstVar_EFS.MAX_ID_FILE_PATH);
			readMaxId = fileService.getMaxId(ConstVar_EFS.MAX_ID_FILE_PATH);
			
			String url = ConstVar_EFS.FETCH_ID_URL+Util.contactUrl("efs_id="+readMaxId,"efs_type="+ConstVar_EFS.EFS_TYPE,"num="+ConstVar_EFS.NUM,"end_id="+ConstVar_EFS.END_ID);
			parseMaxIdUrlInfo(url);
			logger.info(url);
			fileService.storeEfsInfoListToFile(efsInfoList, filePath, false);
			
			//写回最大id文件
			if(writeMaxId>=readMaxId){
//				maxIdfileService.setMaxId(writeMaxId, ConstVar_EFS.MAX_ID_FILE_PATH);
				fileService.setMaxId(writeMaxId, ConstVar_EFS.MAX_ID_FILE_PATH);
			}
		}
	}
	
	
	
	private void parseMaxIdUrlInfo(String url) throws ExceptionCommonBase{
		try {
			String urlContent = WebUtils.http(url, "GET", "utf-8", null, null, null);
			ObjectMapper jsonMapper = new ObjectMapper();
            JsonNode jn = jsonMapper.readTree(urlContent);
            if(jn.get("ext")!=null && jn.get("ext").get("list_efs")!=null
                    && jn.get("ext").get("max_id")!=null){
                Iterator<JsonNode> it = jn.get("ext").get("list_efs").iterator();
                while(it.hasNext()){
                    JsonNode jn2 = (JsonNode) it.next();  
                    EfsInfo efsInfo = new EfsInfo();
                    efsInfo.setEfs_id(jn2.get("efs_id").getLongValue());
                    efsInfo.setEfs_type(jn2.get("efs_type").getTextValue());
//                    efsInfo.setEfs_type(jn2.get("efs_type").getLongValue()+"");
                    efsInfo.setFile_name(jn2.get("file_name").getTextValue());
                    efsInfo.setType(EfsInfoFromType.fromUrl);//从url中拉取的标示
                    efsInfoList.add(efsInfo);
                }
                writeMaxId = jn.get("ext").get("max_id").getLongValue();
            }else{
            	throw new ExceptionCommonBase(-1, "同步数据的接口访问出错...");
            }
		} catch (Exception e) {
			logger.error(e);
			throw ExceptionCommonBase.throwExceptionCommonBase(e);
		} 
	}
	
	/**
	 * 判断该线程对应的拉取文件是否为空
	 */
	public boolean isFetchFileEmpty(String filePath){
		return fileService.isFetchFileEmpty(filePath);
//		return true;
	}
	
	/**
	 * 拉取线程对应的拉取文件中的文件, 如果不为空则拉取, 为空则填充该线程对应的拉取文件
	 */
	public void fetchFile() throws ExceptionCommonBase{
		String filePath = ConstVar_EFS.THREAD_FETCH_BASE_FILE_PATH + threadId;
		
		//判断线程对应的拉取文件是否为空
		efsInfoList = fileService.getEfsInfosFromFile(filePath);
		if(efsInfoList.size()==0){
			fillFetchFile(filePath);
		}
		
		
		//使用责任链模式开始拉取文件
		for(EfsInfo efsInfo : efsInfoList){
			
			ChainObject chainObject = new ChainObject();
			chainObject.put("efsInfo", efsInfo);
			chainObject.put("currentThread", this);
			
			FilterChain filterChain = new ApplicationFilterChain();
			
			Filter filePathListHandler = new FilePathListFilter();
			Filter checkFileExistsHandler1 = new CheckFileExistsFilter();
			Filter crawlerFileHandler = new CrawlerFileFilter();
			Filter checkFileExistsHandler2 = new CheckFileExistsFilter();
			
			filterChain.addFilter(filePathListHandler);
			filterChain.addFilter(checkFileExistsHandler1);
			filterChain.addFilter(crawlerFileHandler);
			filterChain.addFilter(checkFileExistsHandler2);
			
			filterChain.doFilter(chainObject);
			
		}
		
	}
	
	/**
	 * 检查每个拉取文件是否拉取完毕
	 */
//	private void checkFetchFile(int i) {
//		String fileName = ConstVar_EFS.THREAD_FETCH_BASE_FILE_PATH+threadId;
//		
//	}

	@Override
	public void run() {
		Utils.initLog4j();
		try {
			while(true){
				Thread.sleep(1000);
				fetchFile();
			}
		} catch (ExceptionCommonBase e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
//		Filter filePathListHandler = new FilePathListFilter();
//		Filter checkFileExistsHandler1 = new CheckFileExistsFilter();
//		Filter crawlerFileHandler = new CrawlerFileFilter();
//		Filter checkFileExistsHandler2 = new CheckFileExistsFilter();
//		
//		filePathListHandler.setSuccessor(checkFileExistsHandler1);
//		checkFileExistsHandler1.setSuccessor(crawlerFileHandler);
//		crawlerFileHandler.setSuccessor(checkFileExistsHandler2);

		//如果配置了重新拉取的文件, 则将需要重新拉去文件中的信息放入线程对应的文件中
		String filePaths = ConstVar_EFS.REFETCH_ERROR_IDS_FILE_PATHS.trim(); 
		String[] refetchFilePaths = filePaths.split(",");
		FileService fileService = new FileService();
		for(String filePath : refetchFilePaths){
			try {
				List<EfsInfo> efsInfos = FileService.getEfsInfosFromFile(filePath);
				int j = 0;
				for(EfsInfo ei : efsInfos){
					String filename = ConstVar_EFS.THREAD_FETCH_BASE_FILE_PATH + j++%ConstVar_EFS.FETCH_THREAD_NUM;
					fileService.writeBackToFilePath(filename, InputErrorFileAppendType.rewrite
								, ei, 1);
				}
				
			} catch (ExceptionCommonBase e) {
				e.printStackTrace();
			}
//			if(ConstVar_EFS.ERROR_IDS_FILE_PATH_404.equals(filePath)){
//				fetchErrorEfsInfosMode = InputErrorFileAppendType.rewrite;
//			}else if(ConstVar_EFS.ERROR_IDS_FILE_PATH_500.equals(filePath)){
//				connectionErrorEfsMode = InputErrorFileAppendType.rewrite;
//			}
//			efsInfosIn = Utils.collectionsAdd(efsInfosIn, efsInfos);
		}
		
        //创建一个可重用固定线程数的线程池
        ExecutorService pool = Executors.newFixedThreadPool(ConstVar_EFS.FETCH_THREAD_NUM);
        //创建实现了Runnable接口对象，Thread对象当然也实现了Runnable接口
        for(int i=0; i<ConstVar_EFS.FETCH_THREAD_NUM; i++){
        	Thread t = new Thread(new CrawlerThread(i));
        	pool.execute(t);
        }
		
	}

}
